package gameBasicElements;

import java.util.LinkedList;

/**
 * @author Tomasz Wiatrowski
 *
 */
@SuppressWarnings("serial")
public abstract class AbstractBoard implements Board {
	private int size, whiteCaptives, blackCaptives;
	private PlayerColor board[][];

	/**
	 * @param size
	 * @return new size x size AbstractBoard
	 */
	public AbstractBoard(int size){
		this.size = size;
		this.whiteCaptives = this.blackCaptives = 0;
		this.board = new PlayerColor[size][size];
		for(int i=0; i<size; ++i)
			for(int j=0; j<size; ++j)
				board[i][j] = null;
	}
	
	/**
	 * @param abstractBoard
	 * @param pos
	 * @param color
	 * @return new AbstarctBoard (abstractBoard after move without update)
	 */
	public AbstractBoard(AbstractBoard abstractBoard, Position pos, PlayerColor color){
		this.size = abstractBoard.getSize();
		this.whiteCaptives = abstractBoard.captivesScore(PlayerColor.WHITE);
		this.blackCaptives = abstractBoard.captivesScore(PlayerColor.BLACK);
		this.board = new PlayerColor[size][size];
		for(int i=0; i<size; ++i)
			for(int j=0; j<size; ++j)
				board[i][j] = abstractBoard.board[i][j];
		if(pos != null)
			board[pos.getX()][pos.getY()] = color;
	}
	
	/**
	 * @param abstractBoard
	 * @param move
	 * @return new AbstractBoard (abstractBoard after move and update)
	 */
	public AbstractBoard(AbstractBoard abstractBoard, Move move){
		this.size = abstractBoard.getSize();
		this.whiteCaptives = abstractBoard.captivesScore(PlayerColor.WHITE);
		this.blackCaptives = abstractBoard.captivesScore(PlayerColor.BLACK);
		this.board = new PlayerColor[size][size];
		for(int i=0; i<size; ++i)
			for(int j=0; j<size; ++j)
				board[i][j] = abstractBoard.board[i][j];
		if(!move.passed()){
			Position movePosition = move.getPosition();
			board[movePosition.getX()][movePosition.getY()] = move.getColor();
			for(Position pos : getNeighbours(movePosition)){
				if(getPlayerColor(pos)!=move.getColor()&&getPlayerColor(pos)!=null){
					LinkedList<Position> captives = new LinkedList<Position>();
					captives = getCaptives(pos);
					if(getPlayerColor(pos) == PlayerColor.BLACK)
						whiteCaptives += captives.size();
					else if(getPlayerColor(pos) == PlayerColor.WHITE)
						blackCaptives += captives.size();
					takeCaptives(captives);
				}
			}
			LinkedList<Position> captives = new LinkedList<Position>();
			captives = getCaptives(move.getPosition());
			if(getPlayerColor(move.getPosition()) == PlayerColor.BLACK)
				whiteCaptives += captives.size();
			else if(getPlayerColor(move.getPosition()) == PlayerColor.WHITE)
				blackCaptives += captives.size();
			takeCaptives(captives);
		}
	}
	
	public LinkedList<Position> getCaptives(Position pos){
		boolean breath = false;
		boolean visited[][] = new boolean[size][size];
		for(int i=0; i<size; ++i)
			for(int j=0; j<size; ++j)
				visited[i][j] = false;
		LinkedList<Position> res = new LinkedList<Position>();
		LinkedList<Position> queue = new LinkedList<Position>();
		queue.add(pos);
		while(!queue.isEmpty()){
			Position temp = queue.getFirst();
			queue.removeFirst();
			res.add(temp);
			visited[temp.getX()][temp.getY()] = true;
			Position[] neighbours = getNeighbours(temp);
			for(Position neighbour : neighbours){
				if(getPlayerColor(neighbour)==null)
					breath = true;
				if(!visited[neighbour.getX()][neighbour.getY()]&&getPlayerColor(temp)==getPlayerColor(neighbour)){
					visited[neighbour.getX()][neighbour.getY()] = true;
					queue.addLast(neighbour);
				}
			}
		}
		if(breath)
			res.clear();
		return res;
	}
	
	public void takeCaptives(LinkedList<Position> captives){
		for(Position pos : captives){
			board[pos.getX()][pos.getY()] = null;
		}
	}

	@Override
	public PlayerColor getPlayerColor(Position pos) {
		return board[pos.getX()][pos.getY()];
	}

	@Override
	public void setPlayerColor(Position pos, PlayerColor color){
		board[pos.getX()][pos.getY()] = color;
	}
	
	@Override
	public int getSize() {
		return size;
	}
	
	public boolean equals(Object o ){
		AbstractBoard ab = (AbstractBoard)o;
		if(size != ab.getSize())
			return false;
		for(int i=0; i<getSize(); ++i)
			for(int j=0; j<getSize(); ++j)
				if(this.getPlayerColor(new Position(i, j)) != ab.getPlayerColor(new Position(i, j)))
					return false;
		return true;
	}
	public int captivesScore(PlayerColor color){
		if(color == PlayerColor.WHITE)
			return whiteCaptives;
		else
			return blackCaptives;
	}

}
